#ifndef _RTEVENT_H_
#define _RTEVENT_H_


#include <QEvent>
#include <QAtomicInt>
#include <QMap>
#include <QDateTime>
#include <QString>

#include "RtGlobal.h"

#include "win32utils.h"

// forward definitions
class RtObject;
class QObject;


/** Base class for RtLab events

 \ingroup RtCore

*/
class RTLAB_BASE_EXPORT RtEvent : public QEvent
{
public:
	enum RtEventType {
		RtEventMin = QEvent::User,
		ObjectDeleted = QEvent::User,
		ObjectUpdated,
		ObjectError,
		WidgetAdd,
		WidgetRemove,
		ChildJobAdded,
		ChildJobRemoved,
        EndSession,
		RtEventMax = QEvent::User + 20
	};

	RtEvent(RtEventType t, QObject* p) : QEvent((QEvent::Type)t), o(p)
	{}
	virtual ~RtEvent(void)
	{}	

	RtEventType rtType() const { return static_cast<RtEventType>(t); }

	QObject*  qObject() const { return o; }

	static bool isRtEvent(QEvent* e)
	{
		int n = static_cast<int>(e->type());
		return (n>=static_cast<int>(RtEventMin) && n<static_cast<int>(RtEventMax));
	}

protected:
	QObject* o;
};

/**
Structure containing error data.
*/
struct RTLAB_BASE_EXPORT RtErrorEntry
{
    /// Date/time of occurence
    QDateTime t;
    /// Name of object causing the error
    QString objectName;
    /// Error type description
    QString type;
    /// Extended description (optional)
    QString descr;


    RtErrorEntry(const QDateTime& at, const QString& aname, const QString& atype) :
        t(at), objectName(aname), type(atype)
    {}
    RtErrorEntry(const QDateTime& at, const QString& aname, const QString& atype, const QString& adesc) :
        t(at), objectName(aname), type(atype), descr(adesc)
    {}
    RtErrorEntry(const RtErrorEntry& e) :
        t(e.t), objectName(e.objectName), type(e.type), descr(e.descr)
    {}
    QString toString() const
    {
        return QString("%1\t%2\t%3\t%4").arg(t.toString()).arg(objectName).arg(type).arg(descr);
    }

};

class RTLAB_BASE_EXPORT RtErrorEvent : public RtEvent
{
public:
    RtErrorEvent(RtObject* obj, const RtErrorEntry& err);
    virtual ~RtErrorEvent();

    const RtErrorEntry& errorEntry() const { return e; }

protected:
    RtErrorEntry e;
};

class RTLAB_BASE_EXPORT RtUpdateFlag
{
    QAtomicInt update_flag_;

protected:
	inline void resetUpdateFlag()
	{
		update_flag_ = 0;
	}

public:
	RtUpdateFlag()
	{}
	~RtUpdateFlag()
	{}

	inline bool needsUpdateNotification()
	{
		return update_flag_.fetchAndAddOrdered(1)==0;
	}
};

class RTLAB_BASE_EXPORT RtEventSinkMap
{
	typedef QMap<QObject*,RtUpdateFlag*> sinkmap_t;
	QMap<QObject*,RtUpdateFlag*> sinkmap;
    critical_section lock;
public:
	RtEventSinkMap();
	~RtEventSinkMap();

	void add(QObject* o, RtUpdateFlag* f)
	{
        auto_lock L(lock);
		sinkmap.insert(o,f);
	}
	void remove(QObject* o)
	{
        auto_lock L(lock);
		sinkmap.remove(o);
	}
	void post(RtEvent::RtEventType t, RtObject* ptr);
	void postUpdate(RtObject* ptr);
	void send(RtEvent::RtEventType t, RtObject* ptr);
};

#endif


